use crate::cljcell::clj_cell::CljCell;
use crate::built_in_functions::my_clojure_interp::{CljFunc, CljRecur, MyClojureInterp, CljFuncParam, CljFuncParamList, MyCljFunc, MyFuncHs, MyCljRecur};
use crate::built_in_functions::util::my_util;
use crate::built_in_functions::rs_funs::RustFuns;
use std::collections::HashMap;
use std::fmt;
use std::rc::Rc;
use std::cell::RefCell;

pub struct MyFunctions;

impl MyFunctions {

    /**
     * 让形参对应实参，返回 Hashtable
     * */
    pub fn get_params<'a>(clj_func_param_list: &'a Vec<Rc<CljFuncParam>>, ps: &'a [Rc<CljCell>]) -> HashMap<String, Rc<CljCell>> {
        let mut ht: HashMap<String, Rc<CljCell>> = HashMap::new();
        for i in 0..clj_func_param_list.len() {
            let p: &Rc<CljFuncParam> = clj_func_param_list.get(i).unwrap();
            unsafe {
                let m: *mut CljFuncParam = Rc::into_raw(p.clone()) as *mut CljFuncParam;
                if !(*m).get_name().is_empty() {
                    ht.insert((*m).get_name().clone(), ps.get(i).unwrap().clone());
                } else if !(*m).get_rest_param().is_empty() {
                    // let ls1: &[Rc<CljCell>] = &ps[i..];
                    // ht.insert((*m).get_rest_param().clone(), Rc::new(CljCell::List(ls1.to_vec())));
                    let mut rs1: Vec<Rc<CljCell>> = Vec::new();
                    let ls1: &[Rc<CljCell>] = &ps[i..];
                    for n in ls1 {
                        match &**n {
                            CljCell::List(vs22) => {
                                for n1 in vs22 {
                                    rs1.push(n1.clone());
                                }
                            },
                            _ => {
                                rs1.push(n.clone());
                            }
                        }
                    }
                    ht.insert((*m).get_rest_param().clone(), Rc::new(CljCell::List(rs1)));
                } else if !(*m).get_clj_func_param_list().is_empty() && (*m).get_clj_func_param_list().len() == 2 {
                    let cell: Rc<CljCell> = ps.get(i).unwrap().clone();
                    match &*cell {
                        CljCell::List(lst1) => {
                            if lst1.len() > 0 {
                                ht.insert((*m).get_clj_func_param_list().get(0).unwrap().get_name().clone(), lst1.get(0).unwrap().clone());
                                ht.insert((*m).get_clj_func_param_list().get(1).unwrap().get_name().clone(), Rc::new(CljCell::List(lst1[1..].to_vec())));
                            } else {
                                ht.insert((*m).get_clj_func_param_list().get(0).unwrap().get_name().clone(), Rc::new(CljCell::Nil));
                                ht.insert((*m).get_clj_func_param_list().get(1).unwrap().get_name().clone(), Rc::new(CljCell::List(Vec::new())));
                            }
                        },
                        CljCell::BracketClj(lst1) => {
                            if lst1.len() > 0 {
                                ht.insert((*m).get_clj_func_param_list().get(0).unwrap().get_name().clone(), lst1.get(0).unwrap().clone());
                                ht.insert((*m).get_clj_func_param_list().get(1).unwrap().get_name().clone(), Rc::new(CljCell::List(lst1[1..].to_vec())));
                            } else {
                                ht.insert((*m).get_clj_func_param_list().get(0).unwrap().get_name().clone(), Rc::new(CljCell::Nil));
                                ht.insert((*m).get_clj_func_param_list().get(1).unwrap().get_name().clone(), Rc::new(CljCell::List(Vec::new())));
                            }
                        },
                        _ => {},
                    }
                }
                let _ = Rc::from_raw(m);
            }
        }
        return ht;
    }
    // pub fn get_params<'a>(CljFuncParamList: &'a Vec<Rc<CljFuncParam>>, ps: &'a [Rc<CljCell>]) -> HashMap<&'a String, Rc<CljCell>> {
    //     let mut ht: HashMap<&String, Rc<CljCell>> = HashMap::new();
    //     for i in 0..CljFuncParamList.len() {
    //         let p: &Rc<CljFuncParam> = CljFuncParamList.get(i).unwrap();
    //         unsafe {
    //             let m: *mut CljFuncParam = Rc::into_raw(p.clone()) as *mut CljFuncParam;
    //             if !(*m).get_name().is_empty() {
    //                 ht.insert((*m).get_name(), ps.get(i).unwrap().clone());
    //             } else if !(*m).get_rest_param().is_empty() {
    //                 let ls1: &[Rc<CljCell>] = &ps[i..];
    //                 ht.insert((*m).get_rest_param(), Rc::new(CljCell::List(ls1.to_vec())));
    //             } else if !(*m).get_clj_func_param_list().is_empty() && (*m).get_clj_func_param_list().len() == 2 {
    //                 let cell: Rc<CljCell> = ps.get(i).unwrap().clone();
    //                 match &*cell {
    //                     CljCell::List(lst1) => {
    //                         ht.insert((*m).get_clj_func_param_list().get(0).unwrap().get_name(), lst1.get(0).unwrap().clone());
    //                         ht.insert((*m).get_clj_func_param_list().get(1).unwrap().get_name(), Rc::new(CljCell::List(lst1[1..].to_vec())));
    //                     },
    //                     CljCell::BracketClj(lst1) => {
    //                         ht.insert((*m).get_clj_func_param_list().get(0).unwrap().get_name(), lst1.get(0).unwrap().clone());
    //                         ht.insert((*m).get_clj_func_param_list().get(1).unwrap().get_name(), Rc::new(CljCell::List(lst1[1..].to_vec())));
    //                     },
    //                     _ => {},
    //                 }
    //             }
    //             let _ = Rc::from_raw(m);
    //         }
    //     }
    //     return ht;
    // }

    pub fn clj_list_symbol(interp: &MyClojureInterp, lst_rs: &Rc<String>, lst: &Vec<Rc<CljCell>>, func_hs: &MyFuncHs, clj_recur: &MyCljRecur, rs: Rc<CljCell>) -> Rc<CljCell> {
        unsafe {
            //let key = Rc::try_unwrap(lst_rs.into()).unwrap();
            let key: String = (**lst_rs).clone();
            if (*interp.ptr).get_contains_key(&key) {
                let my_clj_func: Option<&MyCljFunc> = (*interp.ptr).get_vs(&key);
                if my_clj_func.is_some() {
                    let my_clj_func1: &MyCljFunc = my_clj_func.unwrap();
                    if my_clj_func1.get_is_override() == &true {
                        let clj_func: Option<&CljFunc> = my_clj_func1.get_clj_func_1((lst.len() as i32) - 1);
                        if clj_func.is_some() {
                            let clj_func1 = clj_func.unwrap();
                            // 参数
                            let clj_func_param_list: &Vec<Rc<CljFuncParam>> = clj_func1.get_func_params();
                            // 函数体
                            let clj_cell_body: &Rc<CljCell> = clj_func1.get_func_body();
                            let ps: &[Rc<CljCell>] = &lst[1..];

                            let ht: HashMap<String, Rc<CljCell>> = MyFunctions::get_params(clj_func_param_list, ps);

                            //let cr = Rc::get_mut(&mut CljRecur).unwrap();
                            clj_recur.set_func_cell_body(clj_cell_body.clone());
                            clj_recur.set_clj_func_param_list(clj_func_param_list.to_vec());

                            for (k, v) in &ht {
                                match &**v {
                                    CljCell::CljList(lss) => {
                                        func_hs.insert(k.to_string(), interp.clj_list(lss, func_hs, clj_recur, rs.clone()));
                                    },
                                    CljCell::Symbol(vs_name) => {
                                    },
                                    _ => {
                                        func_hs.insert(k.to_string(), v.clone());
                                    },
                                }
                            }

                            let myrs: Rc<CljCell> = interp.eval(&clj_cell_body, func_hs, clj_recur, rs.clone());
                            return myrs;
                        }
                    } else {
                        let clj_func: &CljFunc = my_clj_func1.get_clj_func();

                        // 参数
                        let clj_func_param_list: &Vec<Rc<CljFuncParam>> = clj_func.get_func_params();
                        // 函数体
                        let clj_cell_body: &Rc<CljCell> = clj_func.get_func_body();
                        let ps: &[Rc<CljCell>] = &lst[1..];

                        let ht: HashMap<String, Rc<CljCell>> = MyFunctions::get_params(clj_func_param_list, ps);
                        //let cr = Rc::get_mut(&mut CljRecur).unwrap();
                        clj_recur.set_func_cell_body(clj_cell_body.clone());
                        clj_recur.set_clj_func_param_list(clj_func_param_list.to_vec());

                        for (k, v) in &ht {
                            match &**v {
                                CljCell::CljList(lss) => {
                                    func_hs.insert(k.to_string(), interp.clj_list(lss, func_hs, clj_recur, rs.clone()));
                                },
                                CljCell::Symbol(vs_name) => {
                                },
                                _ => {
                                    func_hs.insert(k.to_string(), v.clone());
                                },
                            }
                            // if let CljCell::CljList(lss) = &**v {
                            //     func_hs.insert(k.to_string(), interp.clj_list(lss, func_hs, CljRecur, rs.clone()));
                            // } else {
                            //     func_hs.insert(k.to_string(), v.clone());
                            // }
                        }

                        // unsafe {
                        //     println!("*************");
                        //     println!("{:?}", *interp.ptr);
                        //     println!("{:?}", *func_hs.ptr);
                        //     println!("{:?}", *clj_recur.ptr);
                        //     println!("{:?}", &clj_cell_body);
                        //     println!("$$$$$$$$$$$$$");
                        // }
                        let myrs:Rc<CljCell> = interp.eval(&clj_cell_body, func_hs, clj_recur, rs.clone());
                        return myrs;
                        //return interp.eval(&clj_cell_body, func_hs, CljRecur, rs.clone());
                    }
                }
            } else if func_hs.contains_key(&key) {
                return func_hs.get(&key).clone();
            }
            else {
                // 直接调用 rust 函数
                match key.as_str() {
                    "println" => RustFuns::rs_println(interp, lst[1].clone(), func_hs, clj_recur, rs.clone()),
                    _ => {},
                }
            }
        }
        return Rc::new(CljCell::Null);
    }

    pub fn clj_list_symbol_1(interp: &MyClojureInterp, lst_rs: &Rc<String>, func_hs: &MyFuncHs, clj_recur: &MyCljRecur, rs: Rc<CljCell>) -> Rc<CljCell> {
        unsafe {
            //let key = Rc::try_unwrap(lst_rs.into()).unwrap();
            let key: String = (**lst_rs).clone();
            if func_hs.contains_key(&key) {
                return func_hs.get(&key).clone();
            }
        }
        return Rc::new(CljCell::Null);
    }

    // pub fn clj_list_symbol(interp: &MyClojureInterp, lst_rs: Rc<String>, lst: &Vec<Rc<CljCell>>, func_hs: &MyFuncHs, CljRecur: &MyCljRecur, rs: CljCell) -> CljCell {
    //     let f1:Option<&Rc<CljCell>> = lst.get(0);
    //     // 判断是否存在 func 中
    //     if f1.is_some() {
    //         let f: &Rc<CljCell> = Rc::try_unwrap(f1.unwrap().into()).unwrap();
    //         let f2: &CljCell = &**f;
    //         if let CljCell::Symbol(n) = f2 {
    //             unsafe {
    //                 let key = Rc::try_unwrap(n.into()).unwrap();
    //                 if (*(*interp).ptr).get_contains_key(&key) {
    //                     let my_clj_func: Option<&MyCljFunc> = (*(*interp).ptr).get_vs(&key);
    //                     if my_clj_func.is_some() {
    //                         let myCljFunc1: &MyCljFunc = my_clj_func.unwrap();
    //                         if myCljFunc1.get_is_override() == &true {
    //                             let CljFunc: Option<&CljFunc> = myCljFunc1.get_clj_func_1((lst.len() as i32) - 1);
    //                             if CljFunc.is_some() {
    //                                 let cljFunc1 = CljFunc.unwrap();
    //                                 // 参数
    //                                 let CljFuncParamList: &Vec<Rc<CljFuncParam>> = cljFunc1.get_func_params();
    //                                 // 函数体
    //                                 let clj_cell_body: &Rc<CljCell> = cljFunc1.get_func_body();
    //                                 let ps: &[Rc<CljCell>] = &lst[1..];
    //                                 let ht: HashMap<&String, Rc<CljCell>> = MyFunctions::get_params(CljFuncParamList, ps);
    //
    //                                 let mut cr = CljRecur.borrow_mut();
    //                                 cr.set_func_cell_body(clj_cell_body.clone());
    //                                 cr.set_clj_func_param_list(CljFuncParamList.to_vec());
    //                                 return (*interp).eval(clj_cell_body.clone(), Rc::new(RefCell::new(ht)), CljRecur, rs);
    //                             }
    //                         } else {
    //                             let CljFunc: &CljFunc = myCljFunc1.get_clj_func();
    //
    //                             // 参数
    //                             let CljFuncParamList: &Vec<Rc<CljFuncParam>> = CljFunc.get_func_params();
    //                             // 函数体
    //                             let clj_cell_body: &Rc<CljCell> = CljFunc.get_func_body();
    //                             let ps: &[Rc<CljCell>] = &lst[1..];
    //                             let ht: HashMap<&String, Rc<CljCell>> = MyFunctions::get_params(CljFuncParamList, ps);
    //
    //                             let mut cr = CljRecur.borrow_mut();
    //                             cr.set_func_cell_body(clj_cell_body.clone());
    //                             cr.set_clj_func_param_list(CljFuncParamList.to_vec());
    //                             return (*interp).eval(clj_cell_body.clone(), Rc::new(RefCell::new(ht)), CljRecur, rs);
    //                         }
    //                     }
    //                 }
    //             }
    //         }
    //     }
    //     return CljCell::Null;
    // }


    // pub fn clj_list_fn(interp: &MyClojureInterp, lst: &Vec<Rc<CljCell>>, func_hs: &MyFuncHs, CljRecur: &MyCljRecur, rs: CljCell) -> CljCell {
    //     let f1:Option<&Rc<CljCell>> = lst.get(0);
    //     // 判断是否存在 func 中
    //     if f1.is_some() {
    //         let f: &Rc<CljCell> = Rc::try_unwrap(f1.unwrap().into()).unwrap();
    //         let f2: &CljCell = &**f;
    //         if let CljCell::CljList(n) = f2 {
    //             let my_clj_func = clj_funs::
    //         }
    //     }
    //     return CljCell::Null;
    // }
}